// Gmsh - Copyright (C) 1997-2019 C. Geuzaine, J.-F. Remacle
//
// See the LICENSE.txt file for license information. Please report all
// issues on https://gitlab.onelab.info/gmsh/gmsh/issues.

#ifndef DISCRETE_FACE_H
#define DISCRETE_FACE_H

#include <algorithm>
#include "GmshConfig.h"
#include "GModel.h"
#include "GFace.h"
#include "discreteVertex.h"
#include "discreteEdge.h"
#include "MTriangle.h"
#include "MElementCut.h"
#include "MEdge.h"
#include "MLine.h"
#include "rtree.h"

#if defined(HAVE_HXT)

extern "C" {
#include "hxt_mesh.h"
#include "hxt_parametrization.h"
#include "hxt_linear_system.h"
#include "hxt_curvature.h"
}

class MElementOctree;

class hxt_reparam_surf {
public:
    MElementOctree *oct;
    mutable RTree<std::pair<MTriangle *, MTriangle *> *, double, 3> rtree3d;
    std::vector<MVertex> v2d;
    std::vector<MVertex> v3d;
    std::vector<MTriangle> t2d;
    std::vector<MTriangle> t3d;
    std::vector<GEdge *> bnd;
    std::vector<GEdge *> emb;
    hxt_reparam_surf() : oct(nullptr) {}
    ~hxt_reparam_surf();
};

#endif

class discreteFace : public GFace {
private:
    bool _checkAndFixOrientation();
#if defined(HAVE_HXT)
    int _currentParametrization;
    std::vector<hxt_reparam_surf> _parametrizations;
    HXTStatus _reparametrizeThroughHxt();
    bool _computeTopologyOfPartition(int nbColors, int *colors, int *nNodes,
                                     int *nodes, double *uv,
                                     std::vector<MVertex *> &c2v,
                                     std::vector<std::vector<MEdge> > &boundaries);
#endif
public:
    discreteFace(GModel *model, int num);
    virtual ~discreteFace() {}
    using GFace::point;
    GPoint point(double par1, double par2) const;
    SPoint2 parFromPoint(const SPoint3 &p, bool onSurface = true) const;
    GPoint closestPoint(const SPoint3 &queryPoint, double maxDistance,
                        SVector3 *normal = nullptr) const;
    GPoint closestPoint(const SPoint3 &queryPoint,
                        const double initialGuess[2]) const;
    SVector3 normal(const SPoint2 &param) const;
    double curvatureMax(const SPoint2 &param) const;
    double curvatures(const SPoint2 &param, SVector3 &dirMax, SVector3 &dirMin,
                      double &curvMax, double &curvMin) const;
    GEntity::GeomType geomType() const { return DiscreteSurface; }
    virtual Pair<SVector3, SVector3> firstDer(const SPoint2 &param) const;
    virtual void secondDer(const SPoint2 &param, SVector3 &dudu, SVector3 &dvdv,
                           SVector3 &dudv) const;
    void createGeometry();
    virtual bool haveParametrization()
    {
#if defined(HAVE_HXT)
        return !_parametrizations.empty();
#else
        return false;
#endif
    }
    virtual void mesh(bool verbose);
    void setBoundEdges(const std::vector<int> &tagEdges);
    void setBoundEdges(const std::vector<int> &tagEdges,
                       const std::vector<int> &signEdges);
    int trianglePosition(double par1, double par2, double &u, double &v) const;
    GPoint intersectionWithCircle(const SVector3 &n1, const SVector3 &n2,
                                  const SVector3 &p, const double &R,
                                  double uv[2]);
};

#endif
